home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / DumpARPCache1.0.1b1 / DumpARPCache.c next >
Encoding:
C/C++ Source or Header  |  1998-03-09  |  10.0 KB  |  330 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        DumpARPCache.c
  3.  
  4.     Contains:    Dumps the system ARP cache to stdout.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. #define qDebug 1
  22.  
  23. /////////////////////////////////////////////////////////////////////
  24. // Pick up the standard C stuff.
  25.  
  26. #include <stdio.h>
  27. #include <string.h>
  28.  
  29. /////////////////////////////////////////////////////////////////////
  30. // Pick up standard OT APIs.
  31.  
  32. #include <OpenTptInternet.h>
  33.  
  34. /////////////////////////////////////////////////////////////////////
  35. // Pick up low-level OT APIs.
  36.  
  37. #include <OpenTptClient.h>
  38. #include <OTDebug.h>
  39.  
  40. /////////////////////////////////////////////////////////////////////
  41. // Pick up the symbolic name of the various OT modules.
  42.  
  43. #include <modnames.h>
  44.  
  45. /////////////////////////////////////////////////////////////////////
  46. // OTDebugStr is not defined in any OT header files, but it is
  47. // exported by the libraries, so we define the prototype here.
  48.  
  49. extern pascal void OTDebugStr(const char* str);
  50.  
  51. /////////////////////////////////////////////////////////////////////
  52. // The following equates are actually exported by <miioccom.h>, but
  53. // they commented out for some reason )-:
  54.  
  55. // #include <miioccom.h>
  56.  
  57. #define MIOC_ND            'c'        /* ioctl's for Mentat's nd device */
  58.  
  59. // The following equates define the two "Name Dispatch" ioctls
  60. // for setting and getting OT internal parameters.
  61.  
  62. #define ND_GET            MIOC_CMD(MIOC_ND, 0)    /* Get a value */
  63. #define ND_SET            MIOC_CMD(MIOC_ND, 1)    /* Set a value */
  64.  
  65. /////////////////////////////////////////////////////////////////////
  66. // The name of the Name Dispatch variables we display.
  67.  
  68. #define ARP_ND_CACHE_REPORT     "arp_cache_report"
  69.     // ARP cache report
  70.  
  71. /////////////////////////////////////////////////////////////////////
  72.  
  73. /////////////////////////////////////////////////////////////////////
  74.  
  75. static OSStatus CreateStatusStream(StreamRef *result)
  76.     // Create a raw stream to which we can send the various
  77.     // status reports.  We do this by opening the IP driver,
  78.     // and pushing the other modules directly on top of it.
  79.     // This arrangement is just for convenience.  We could
  80.     // just have easily opened the null driver and pushed
  81.     // the module of interest on top.
  82. {
  83.     OSStatus err;
  84.     OSStatus junk;
  85.     StreamRef strm;
  86.     
  87.     // Open up a raw stream to the IP device.
  88.     
  89.     strm = OTStreamOpen(MI_IP_NAME, 0, &err);
  90.     if (err == noErr) {
  91.         // To make this simpler we're going to use sync/blocking mode.
  92.         
  93.         OTStreamSetBlocking(strm);
  94.         OTStreamSetSynchronous(strm);
  95.     }
  96.  
  97.     // Push the various modules of interest on top of the stream.
  98.     
  99.     if (err == noErr) {
  100.         err = OTStreamIoctl(strm, I_PUSH, MI_ARPM_NAME);
  101.     }
  102.     if (err == noErr) {
  103.         err = OTStreamIoctl(strm, I_PUSH, MI_TCPM_NAME);
  104.     }
  105.     if (err == noErr) {
  106.         err = OTStreamIoctl(strm, I_PUSH, MI_UDPM_NAME);
  107.     }
  108.     
  109.     // Clean up and setup result to either be valid or nil.
  110.     
  111.     if (err == noErr) {
  112.         *result = strm;
  113.     } else {
  114.         if (strm != kOTInvalidStreamRef) {
  115.             junk = OTStreamClose(strm);
  116.             OTAssert("CreateStatusStream: OTStreamClose failed", junk == noErr);
  117.         }
  118.         *result = kOTInvalidStreamRef;
  119.     }
  120.     return err;
  121. }
  122.  
  123. static void DumpNameDispatchReport(StreamRef strm, char *ndName, char *userVisibleName)
  124.     // Dumps a Name Dispatch (ND) report to standard out.  strm
  125.     // is a raw stream that contains the module from which the
  126.     // report is to be extracted.  ndName is the Name Dispatch
  127.     // name of the report.  userVisibleName is the name of the report
  128.     // in user terminology (only used to make the printout sensible).
  129.     //
  130.     // The general  principle is as follows.  We send an Name Dispatch ioctl
  131.     // down strm.  The relevant module catches the ioctl, creates the
  132.     // report (as text, with null characters as the line terminator)
  133.     // and sends it back to us.  The stream head copies the data back
  134.     // into our ioctl buffer.
  135.     //
  136.     // The only tricky thing is to judge the size of the buffer to
  137.     // allocate.  We do this in two passes.  In the first pass,
  138.     // we create a minimum sized buffer and use it for the ioctl.
  139.     // The ioctl result comes back as the size of the buffer we
  140.     // should have allocated.  We then reallocate the buffer
  141.     // and issue the ioctl again.  Obviously the size of the report
  142.     // could change between successive ioctls, so we have to
  143.     // loop until it works correctly.
  144. {
  145.     OSStatus err;
  146.     struct strioctl ndIoctl;
  147.     SInt32 i;
  148.     char *dataBuffer;
  149.     SInt32 dataBufferSize;
  150.     SInt32 minimumDataBufferSize;
  151.     SInt32 ioctlResult;
  152.     Boolean done;
  153.     
  154.     printf("Dumping %s (%s)\n\n", userVisibleName, ndName);
  155.     
  156.     // Allocate a minimum sized buffer for the first ioctl call.
  157.     // It's the length of the string, plus space for the null terminator,
  158.     // plus space for an extra null.
  159.     
  160.     dataBuffer = nil;
  161.     dataBufferSize = OTStrLength(ndName) + 1 + 1;
  162.     minimumDataBufferSize = dataBufferSize;
  163.     
  164.     done = false;
  165.     
  166.     do {
  167.         OTAssert("DumpNameDispatchReport: dataBuffer should have been disposed in the looping case", dataBuffer == nil);
  168.     
  169.         // Allocate the memory according to our current guess as to dataBufferSize.
  170.  
  171.         err = noErr;
  172.         dataBuffer = OTAllocMem( dataBufferSize );
  173.         if (dataBuffer == nil) {
  174.             err = kENOMEMErr;
  175.         }
  176.         
  177.         if (err == noErr) {
  178.  
  179.             // Copy the name of the ND variable we're trying
  180.             // to get into our buffer.
  181.  
  182.             OTStrCopy(dataBuffer, ndName);
  183.             
  184.             // Now put a null after the name in the data buffer.
  185.             // This is because ND requests must be made up
  186.             // of two strings, right after one another in the
  187.             // buffer.
  188.             
  189.             dataBuffer[ OTStrLength(ndName) + 1 ] = 0;
  190.         
  191.             // The ND_GET ioctl returns a value and sets ic_len.  A negative
  192.             // value is an error and you can give up now (-:  The rule for
  193.             // positive values is a bit weirder.  ic_len is always set
  194.             // to the amount of data that is actually returned.  If the
  195.             // data available exceeds the available buffer space (as
  196.             // defined by the ic_len on input), the ioctl returns
  197.             // a positive number that is the amount of buffer space
  198.             // needed.  So we first call it with a minimal buffer
  199.             // then give it the buffer space it requires.  Obviously
  200.             // there's a concurrency race here; we loop until our
  201.             // buffer is big enough.
  202.  
  203.             // First get the size of data buffer we need to allocate.
  204.             
  205.             ndIoctl.ic_cmd = ND_GET;
  206.             ndIoctl.ic_timout = 0;
  207.             ndIoctl.ic_len = dataBufferSize;
  208.             ndIoctl.ic_dp = dataBuffer;
  209.  
  210.             ioctlResult = OTStreamIoctl(strm, I_STR, &ndIoctl);
  211.             
  212.             // printf("••• dataBufferSize = %ld, ic_len = %ld, ioctlResult = %ld\n", dataBufferSize, ndIoctl.ic_len, ioctlResult);
  213.             
  214.             if (ioctlResult < 0) {
  215.                 err = ioctlResult;
  216.             } else {
  217.                 if (ioctlResult <= dataBufferSize) {
  218.                 
  219.                     // The report fit into dataBuffer, so let's
  220.                     // just print it out and we're done.  Remember that
  221.                     // the report uses nulls as line terminators, so we 
  222.                     // have to print it character by character )-:
  223.                     
  224.                     err = noErr;
  225.                     for (i = 0; i < ndIoctl.ic_len; i++) {
  226.                         if (dataBuffer[i] == 0) {
  227.                             putchar('\n');
  228.                         } else {
  229.                             putchar(dataBuffer[i]);
  230.                         }
  231.                     }
  232.                     done = true;
  233.                 } else {
  234.                 
  235.                     // The allocated data buffer is the wrong size,
  236.                     // so we deallocate and loop.
  237.                     
  238.                     OTAssert("DumpNameDispatchReport: Should have a data buffer here", dataBuffer != nil);
  239.                     OTFreeMem(dataBuffer);
  240.                     dataBuffer = nil;
  241.  
  242.                     // In this case, the ioctl has returned the size that
  243.                     // the buffer /should have been/ to get all the info.  We
  244.                     // set dataBufferSize to that value and loop.
  245.                     //
  246.                     // The buffer that we allocate should be able to hold
  247.                     // the request (ie the string (with null terminator)
  248.                     // and the second null).  If the ioctlResult comes
  249.                     // back too small, we're going to die when copying
  250.                     // the string into the new buffer.  However, the ioctlResult
  251.                     // should be bigger than the buffer, because otherwise it
  252.                     // wouldn't have failed.  So we just assert that
  253.                     // ioctlResult >= minimumDataBufferSize, just to be sure.
  254.  
  255.                     OTAssert("DumpNameDispatchReport: ioctl failed but it should have succeeded", ioctlResult >= minimumDataBufferSize);
  256.  
  257.                     dataBufferSize = ioctlResult;
  258.                 }
  259.             }
  260.         }
  261.     } while (err == noErr & ! done );
  262.     
  263.     // Clean up.
  264.     if (dataBuffer != nil) {
  265.         OTFreeMem(dataBuffer);
  266.     }
  267.     
  268.     if (err == noErr) {
  269.         printf("Success!\n");
  270.     } else {
  271.         printf("Failed with error %ld.\n", err);
  272.     }
  273.     printf("\n\n");
  274. }
  275.  
  276. /////////////////////////////////////////////////////////////////////
  277.  
  278. void main(void)
  279. {
  280.     OSStatus err;
  281.     OSStatus junk;
  282.     StreamRef strm;
  283.     InetInterfaceInfo junkInfo;
  284.     
  285.     printf("Hello Cruel World!\n");
  286.     printf("DumpARPCache -- Dumps the Open Transport ARP cache to stdout\n\n");
  287.     
  288.     err = InitOpenTransport();
  289.     
  290.     if (err == noErr) {
  291.     
  292.         err = OTInetGetInterfaceInfo(&junkInfo, kDefaultInetInterface);
  293.         if (err != noErr) {
  294.             printf("This report is not meaningful unless the TCP/IP stack is loaded.\n");
  295.             printf("You can still get the report, it just low on useful content.\n");
  296.             printf("\n");
  297.             err = noErr;
  298.         }
  299.         
  300.         if (err == noErr) {
  301.         
  302.             // Create the raw stream from which we're going to extract
  303.             // report information.  This stream contains all the TCP/IP
  304.             // modules ganged together in one convenient package.
  305.         
  306.             err = CreateStatusStream(&strm);
  307.             if (err == noErr) {
  308.             
  309.                 // Get and dump each report, one at a time.
  310.         
  311.                 DumpNameDispatchReport(strm, ARP_ND_CACHE_REPORT, "ARP Cache");
  312.                 
  313.                 // Clean up.
  314.                 
  315.                 junk = OTStreamClose(strm);
  316.                 OTAssert("main: OTStreamClose failed", junk == noErr);
  317.             }
  318.         }
  319.         
  320.         CloseOpenTransport();
  321.     }
  322.     
  323.     if (err == noErr) {
  324.         printf("Success.\n");
  325.     } else {
  326.         printf("Failed with error %d.\n", err);
  327.     }
  328.     printf("Done.  Press command-Q to Quit.\n");
  329. }
  330.